package org.byd.dmsja.utils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

// 层级数据
public class SNEHierData<TRecord> {

    // 记录列表。
    public List<TRecord> recordList;
    // 主键值选择器。
    public Function<TRecord, Object> idSelector;
    // 父键值选择器。
    public Function<TRecord, Object> parentIdSelector;

    // 构造函数
    public SNEHierData(
            List<TRecord> recordList,
            Function<TRecord, Object> idSelector,
            Function<TRecord, Object> parentIdSelector
    ) {
        this.recordList = recordList;
        this.idSelector = idSelector;
        this.parentIdSelector = parentIdSelector;
    }

    // 获取主键值。
    public Object getId(TRecord record) {
        return this.idSelector == null ? null : this.idSelector.apply(record);
    }

    // 获取父键值。
    public Object getParentId(TRecord record) {
        return this.parentIdSelector == null ? null : this.parentIdSelector.apply(record);
    }

    // 当前记录是否有父记录。
    public Boolean hasParent(TRecord currentRecord) {
        var parent1Record = this.getParent1Record(currentRecord);
        var rlt = parent1Record != null;
        return rlt;
    }

    // 当前记录是否有子记录。
    public Boolean hasChild(TRecord currentRecord) {
        var rlt = this.recordList.stream()
                .anyMatch(x -> Objects.equals(this.getParentId(x), this.getId(currentRecord)));
        return rlt;
    }

    // 获取当前记录的父一级记录。
    public TRecord getParent1Record(TRecord currentRecord) {
        var result = this.recordList.stream()
                .filter(x -> Objects.equals(this.getId(x), this.getParentId(currentRecord)))
                .findFirst().orElse(null);
        return result;
    }

    // 获取当前记录的子一级记录列表。
    public List<TRecord> getChild1RecordList(TRecord currentRecord) {
        var result = this.recordList.stream()
                .filter(x -> Objects.equals(this.getParentId(x), this.getId(currentRecord)))
                .collect(Collectors.toList());
        return result;
    }

    // 获取顶级记录列表。
    public List<TRecord> getTopRecordList() {
        var result = this.recordList.stream().filter(x -> !this.hasParent(x)).collect(Collectors.toList());
        return result;
    }



    // 获取末级记录列表。
    public List<TRecord> getDeepRecordList() {
        var result = this.recordList.stream().filter(x -> this.hasChild(x)).collect(Collectors.toList());
        return result;
    }

    // 获取当前记录的所有父记录列表。
    public List<TRecord> getAllParentRecordList(TRecord currentRecord) {
        List<TRecord> result = new ArrayList<>();
        this.getAllParentRecordList_Callback(currentRecord, result);
        return result;
    }

    private void getAllParentRecordList_Callback(TRecord currentRecord, List<TRecord> result) {
        var parentRecord = this.getParent1Record(currentRecord);
        if (parentRecord != null) {
            result.add(parentRecord);
            this.getAllParentRecordList_Callback(parentRecord, result);
        }
    }

    // 获取当前记录的所有子记录列表。
    public List<TRecord> getAllChildRecordList(TRecord currentRecord) {
        List<TRecord> result = new ArrayList<>();
        this.getAllChildRecordList_Callback(currentRecord, result);
        return result;
    }

    private void getAllChildRecordList_Callback(TRecord currentRecord, List<TRecord> result) {
        var child1RecordList = this.getChild1RecordList(currentRecord);
        child1RecordList.forEach(x -> {result.add(x); this.getAllParentRecordList_Callback(x, result);});
    }

    // 获取当前记录的深度。
    public Integer getDepth(TRecord currentRecord) {
        this.getDepth_Result = 0;
        this.getDepth_Callback(currentRecord);
        return getDepth_Result;
    }

    private void getDepth_Callback(TRecord currentRecord) {
        var parent1Record = this.getParent1Record(currentRecord);
        if (parent1Record != null) {
            this.getDepth_Result = this.getDepth_Result + 1;
            this.getDepth_Callback(parent1Record);
        }
    }

    private Integer getDepth_Result = 0;

    // 获取当前记录的路径（路径分隔符为大于号）。
    public String getPath(TRecord currentRecord, Function<TRecord, Object> pathSelector) {
        return this.getPath(currentRecord, pathSelector, ">");
    }

    // 获取当前记录的路径。
    public String getPath(TRecord currentRecord, Function<TRecord, Object> pathSelector, String deli) {
        this.getPath_Result = new ArrayList<>();
        this.getPath_Callback(currentRecord);
        Collections.reverse(this.getPath_Result);
        var result = this.getPath_Result.stream()
                .map(x -> pathSelector.apply(x))
                .map(x -> x == null ? "" : x.toString())
                .collect(Collectors.joining(deli));
        return result;
    }

    private void getPath_Callback(TRecord currentRecord) {
        this.getPath_Result.add(currentRecord);
        var parent1Record = this.getParent1Record(currentRecord);
        if (parent1Record != null) {
            this.getPath_Callback(parent1Record);
        }
    }

    private List<TRecord> getPath_Result = new ArrayList<>();

    // 遍历当前的子一级记录（不遍历自己）。
    public void forEachChild1(TRecord currentRecord, Consumer<TRecord> consumer) {
        this.forEachChild1(currentRecord, consumer, false);
    }

    // 遍历当前的子一级记录。
    public void forEachChild1(TRecord currentRecord, Consumer<TRecord> consumer, Boolean selfIf) {
        var child1RecordList = this.getChild1RecordList(currentRecord);
        if (selfIf) {consumer.accept(currentRecord);}
        child1RecordList.forEach(x -> consumer.accept(x));
    }

    // 遍历当前的所有子记录(不遍历自己)。
    public void forEachChildAll(TRecord currentRecord, Consumer<TRecord> consumer) {
        this.forEachChildAll(currentRecord, consumer, false);
    }

    // 遍历当前的所有子记录。
    public void forEachChildAll(TRecord currentRecord, Consumer<TRecord> consumer, Boolean selfIf) {
        var childAllRecordList = this.getAllChildRecordList(currentRecord);
        if (selfIf) {consumer.accept(currentRecord);}
        childAllRecordList.forEach(x -> consumer.accept(x));
    }

    // 遍历当前的所有父记录（不遍历自己）。
    public void forEachParentAll(TRecord currentRecord, Consumer<TRecord> consumer) {
        this.forEachParentAll(currentRecord, consumer, false);
    }

    // 遍历当前的所有父记录。
    public void forEachParentAll(TRecord currentRecord, Consumer<TRecord> consumer, Boolean selfIf) {
        var parentAllRecordList = this.getAllParentRecordList(currentRecord);
        if (selfIf) {consumer.accept(currentRecord);}
        parentAllRecordList.forEach(x -> consumer.accept(x));
    }

    // 对原始记录进行排序(正序，null值视为最小)
    public void sortRecordList(Function<TRecord, Object> sortNoSelector) {
        this.sortRecordList(sortNoSelector, false, true);
    }

    // 对原始记录进行排序(倒序，null值视为最小)
    public void sortRecordList(Function<TRecord, Object> sortNoSelector, Boolean isDescending) {
        this.sortRecordList(sortNoSelector, isDescending, true);
    }

    // 对原始记录进行排序
    public void sortRecordList(Function<TRecord, Object> sortNoSelector, Boolean isDescending, Boolean nullLeast) {
        List<TRecord> result = new ArrayList<>();
        var topRecordList = this.getTopRecordList();
        topRecordList.sort((a, b) -> SNE.compareEx(sortNoSelector.apply(a), sortNoSelector.apply(b), isDescending,
                nullLeast));
        topRecordList.forEach(t -> this.sortRecordList_Callback(t, sortNoSelector, isDescending, nullLeast, result));
        this.recordList = result;
    }

    private void sortRecordList_Callback(TRecord currentRecord, Function<TRecord, Object> sortNoSelector,
                                         Boolean isDescending, Boolean nullLeast, List<TRecord> result) {
        result.add(currentRecord);
        var child1RecordList = this.getChild1RecordList(currentRecord);
        child1RecordList.sort((a, b) -> SNE.compareEx(sortNoSelector.apply(a), sortNoSelector.apply(b), isDescending));
        child1RecordList.forEach(t -> this.sortRecordList_Callback(t, sortNoSelector, isDescending, nullLeast, result));
    }
}
